package titt.service;

import java.util.HashMap;

import titt.service.invoke.MethodParser;
import titt.service.os.ServiceObjectServer;
import titt.service.proxy.server.ServerProxy;
import titt.service.threading.MultipleTITTThreader;

public class LinkedRegistrationStrategy implements RegistrationStrategy {

	private final ServiceMechanics sm;
	private final HashMap<String, ServiceObjectServer> serviceMap = new HashMap<String, ServiceObjectServer>();
	private final HashMap<Object, ServiceObjectServer> objectMap = new HashMap<Object, ServiceObjectServer>();
	
	private int i = 0;
	private String rid;
	private ServiceObjectServer base;
	
	public LinkedRegistrationStrategy(ServiceMechanics sm) {
		this.sm = sm;
	}
	
	@Override
	public void register(Object o, MethodParser mp, String... tokens) throws Exception {
		synchronized (this) {
			if(base == null)
				base = registerBase(mp);
		}
		ServiceObjectServer sos = sm.register(o, mp, base.getServiceID(), tokens);
		synchronized (this) {
			serviceMap.put(sos.getServiceID(), sos);
			objectMap.put(sos.getObject(), sos);
		}
	}

	@Override
	public void unregister(Object o, boolean lazy) throws Exception {
		synchronized (this) {			
			ServiceObjectServer sos = objectMap.remove(o);
			if(sos != null)
				serviceMap.remove(sos.getServiceID());
		}
		sm.unregister(o, lazy);
		checkBase(lazy);
	}
	
	private void checkBase(boolean lazy) throws Exception {
		Object obj;
		synchronized (this) {
			if(!serviceMap.isEmpty()) return;
			obj = base.getObject();
			base = null;
		}
		sm.unregister(obj, lazy);
	}
	
	private ServiceObjectServer registerBase(MethodParser mp) throws Exception {
		ServiceObjectServer base = sm.register(new Object(), mp, generateKey());
		final String baseKey = base.getServiceID();
		MultipleTITTThreader.get().execute(new Runnable() {
			public void run() {
				try {
					while(invokeAndRepond(baseKey));	
				}
				catch(Exception e) {}
			}
		});
		return base;

	}
	
	private synchronized String[] generateKey() throws Exception {
		if(rid == null)
			rid = ServerProxy.get().gensym();
		return new String[]{"internal", "registration", rid + "x" + i++};
	}
	
	private boolean invokeAndRepond(String baseKey) throws Exception {
		ServicePackage pack = ServerProxy.get().withdraw(baseKey);

		synchronized (this) {
			if(pack == null || base == null) return false;
			
			ServiceObjectServer sos = pack.getServiceID().equals(base.getServiceID())? base : serviceMap.get(pack.getServiceID());
			
			if(sos == null) return true;
			
			MultipleTITTThreader.get().execute(sm.futureHandlePackage(sos, pack));
		}

		return true;
	}

}
